package mirrormonkey.state;

import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import mirrormonkey.state.tools.identity.entities.IdAwareTestBox;
import mirrormonkey.state.tools.identity.entities.ServerIdAwareTestBox;
import mirrormonkey.state.tools.identity.entities.SpecialServerIdAwareTestBox;

import org.junit.Test;

import com.jme3.math.Vector3f;

public class IdentityAwarenessTest extends SingleClientTestProto {

	public class BoxData {

		public ServerIdAwareTestBox serverBox;

		public IdAwareTestBox clientBox;

	}

	public BoxData[] cornerBoxes;

	public BoxData jumpingBox;

	@Override
	public void createBoxes() {
		cornerBoxes = new BoxData[2];
		BoxData d = createBox(new ServerIdAwareTestBox(), new Vector3f(2, 0, 0));
		cornerBoxes[0] = d;
		d = createBox(new ServerIdAwareTestBox(), new Vector3f(-2, 0, 0));
		cornerBoxes[1] = d;

		jumpingBox = createBox(new SpecialServerIdAwareTestBox(), Vector3f.ZERO);
		sleepNoInterrupt(100);
		processEvents();

		sleepNoInterrupt(100);
		processEvents();
	}

	private BoxData createBox(ServerIdAwareTestBox serverBox, Vector3f vector3f) {
		BoxData d = new BoxData();
		d.serverBox = serverBox;
		serverApplication.getRootNode().attachChild(d.serverBox);
		d.serverBox.setLocalTranslation(vector3f);
		serverApplication.coreModule.addMapping(getFirstConnection(),
				d.serverBox, IdAwareTestBox.class);

		sleepNoInterrupt(100);
		processEvents();

		d.clientBox = (IdAwareTestBox) clientApplication.appState.entityProvider
				.getData(d.serverBox.getData().id).entity;
		return d;
	}

	@Override
	public void removeBoxes() {
		for (BoxData d : cornerBoxes) {
			serverApplication.coreModule.removeMapping(getFirstConnection(),
					d.serverBox);
		}
		serverApplication.coreModule.removeMapping(getFirstConnection(),
				jumpingBox.serverBox);
		sleepNoInterrupt(100);
		processEvents();

		sleepNoInterrupt(100);
		processEvents();
	}

	@Test
	public void testIdentityAwareness() {
		long lastTime = System.currentTimeMillis();

		int i = 1;
		long time = 0;
		while (time <= 10000) {
			long delta = System.currentTimeMillis() - lastTime;
			time += delta;
			lastTime = System.currentTimeMillis();

			i = i == 1 ? 0 : 1;
			jumpingBox.serverBox.setOtherBox(cornerBoxes[i].serverBox);

			sleepNoInterrupt(500);

			assertSame(cornerBoxes[i].clientBox, jumpingBox.clientBox.otherBox);
		}
	}

	@Test
	public void testIdentityAwareNullValue() {
		long lastTime = System.currentTimeMillis();

		int i = 0;
		long time = 0;
		while (time <= 10000) {
			long delta = System.currentTimeMillis() - lastTime;
			time += delta;
			lastTime = System.currentTimeMillis();

			i = ++i % 3;
			BoxData targetBox = i == 2 ? null : cornerBoxes[i];
			jumpingBox.serverBox.setOtherBox(targetBox == null ? null
					: targetBox.serverBox);

			sleepNoInterrupt(500);

			assertSame(targetBox == null ? null : targetBox.clientBox,
					jumpingBox.clientBox.otherBox);
		}
	}

	@Test
	public void testIdentityTrack() {
		long lastTime = System.currentTimeMillis();

		int i = 1;
		int oldI = 0;
		long time = 0;
		while (time <= 10000) {
			int newI = (int) (System.currentTimeMillis() / 500);
			long delta = System.currentTimeMillis() - lastTime;
			time += delta;
			lastTime = System.currentTimeMillis();

			if (newI != oldI) {
				oldI = newI;
				jumpingBox.clientBox.reset();
				i = i == 1 ? 0 : 1;
				jumpingBox.serverBox
						.setTrackedOtherBox(cornerBoxes[i].serverBox);

				sleepNoInterrupt(100);
			}

			sleepNoInterrupt(10);

			assertSame(cornerBoxes[i].clientBox,
					jumpingBox.clientBox.trackedOtherBox);
			// TODO double message send workarround
			assertTrue(jumpingBox.clientBox.setterCalls < 3);
		}
	}

	@Test
	public void testIdentityTrackNull() {
		long lastTime = System.currentTimeMillis();

		int i = 1;
		int oldI = 0;
		long time = 0;
		while (time <= 10000) {
			int newI = (int) (System.currentTimeMillis() / 500);
			long delta = System.currentTimeMillis() - lastTime;
			time += delta;
			lastTime = System.currentTimeMillis();

			if (newI != oldI) {
				oldI = newI;
				jumpingBox.clientBox.reset();
				i = ++i % 3;
				jumpingBox.serverBox.setTrackedOtherBox(i == 2 ? null
						: cornerBoxes[i].serverBox);

				sleepNoInterrupt(100);
			}

			sleepNoInterrupt(10);

			assertSame(i == 2 ? null : cornerBoxes[i].clientBox,
					jumpingBox.clientBox.trackedOtherBox);
			// TODO double message send workarround
			assertTrue(jumpingBox.clientBox.setterCalls < 3);
		}
	}

}
